apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: d8allowedprocmount
  labels:
    heritage: deckhouse
    module: admission-policy-engine
    security.deckhouse.io: security-policy
  annotations:
    metadata.gatekeeper.sh/title: "Proc Mount"
    metadata.gatekeeper.sh/version: 1.0.1
    description: >-
      Controls the allowed `procMount` types for the container. Corresponds to
      the `allowedProcMountTypes` field in a PodSecurityPolicy. For more
      information, see
      https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes
spec:
  crd:
    spec:
      names:
        kind: D8AllowedProcMount
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          type: object
          description: >-
            Controls the allowed `procMount` types for the container. Corresponds to
            the `allowedProcMountTypes` field in a PodSecurityPolicy. For more
            information, see
            https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes
          properties:
            allowedProcMount:
              type: string
              description: >-
                Defines the strategy for the security exposure of certain paths
                in `/proc` by the container runtime. Setting to `Default` uses
                the runtime defaults, where `Unmasked` bypasses the default
                behavior.
              enum:
                - Default
                - Unmasked
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package d8.security_policies

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            allowedProcMount := get_allowed_proc_mount(input)
            not input_proc_mount_type_allowed(allowedProcMount, c)
            msg := sprintf("ProcMount type is not allowed, container: %v. Allowed procMount types: %v", [c.name, allowedProcMount])
        }

        input_proc_mount_type_allowed(allowedProcMount, c) {
            allowedProcMount == "default"
            count(c.securityContext.procMount) == 0
        }
        input_proc_mount_type_allowed(allowedProcMount, c) {
            allowedProcMount == "default"
            lower(c.securityContext.procMount) == "default"
        }
        input_proc_mount_type_allowed(allowedProcMount, c) {
            allowedProcMount == "unmasked"
        }

        input_containers[c] {
            c := input.review.object.spec.containers[_]
            c.securityContext.procMount
        }
        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
            c.securityContext.procMount
        }
        input_containers[c] {
            c := input.review.object.spec.ephemeralContainers[_]
            c.securityContext.procMount
        }

        get_allowed_proc_mount(arg) = out {
            not arg.parameters
            out = "default"
        }
        get_allowed_proc_mount(arg) = out {
            not arg.parameters.allowedProcMount
            out = "default"
        }
        get_allowed_proc_mount(arg) = out {
            arg.parameters.allowedProcMount
            not valid_proc_mount(arg.parameters.allowdeProcMount)
            out = "default"
        }
        get_allowed_proc_mount(arg) = out {
            valid_proc_mount(arg.parameters.allowedProcMount)
            out = lower(arg.parameters.allowedProcMount)
        }

        valid_proc_mount(str) {
            lower(str) == "default"
        }
        valid_proc_mount(str) {
            lower(str) == "unmasked"
        }
